package com.java.mall_imooc.service.impl;

import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.lang.Snowflake;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.github.pagehelper.PageHelper;
import com.github.pagehelper.PageInfo;
import com.java.mall_imooc.common.enums.OrderStatusEnum;
import com.java.mall_imooc.common.enums.PaymentTypeEnum;
import com.java.mall_imooc.common.enums.ResultEnum;
import com.java.mall_imooc.common.exception.RRException;
import com.java.mall_imooc.common.utils.Constant;
import com.java.mall_imooc.common.utils.PageUtils;
import com.java.mall_imooc.common.utils.R;
import com.java.mall_imooc.entity.*;
import com.java.mall_imooc.mapper.OrderDao;
import com.java.mall_imooc.service.*;
import com.java.mall_imooc.vo.OrderItemVo;
import com.java.mall_imooc.vo.OrderVo;
import lombok.AllArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.BeanUtils;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.math.BigDecimal;
import java.util.*;
import java.util.stream.Collectors;

@Service("orderService")
@AllArgsConstructor
@Slf4j
public class OrderServiceImpl extends ServiceImpl<OrderDao, Order> implements OrderService {
    private OrderItemService orderItemService;
    private ShippingService shippingService;
    private CartService cartService;
    private ProductService productService;
    private Snowflake snowflake;

    @Override
    public PageUtils queryPage(Order order, Integer pageNum, Integer pageSize) {
        IPage<Order> page = this.page(
                new Page<>(pageNum, pageSize),
                new QueryWrapper<Order>() // 拼接查询条件
        );

        return new PageUtils(page);
    }

    @Override
    public R<PageInfo> list(Integer userId, Integer pageNum, Integer pageSize) {
        PageHelper.startPage(pageNum, pageSize);
        List<Order> orders = this.baseMapper.selectList(new LambdaQueryWrapper<Order>().eq(Order::getUserId, userId));
        // 查询orderItemList
        List<Long> orderNos = orders.stream().map(Order::getOrderNo).collect(Collectors.toList());
        List<OrderItem> orderItems = orderItemService.list(new LambdaQueryWrapper<OrderItem>().in(OrderItem::getOrderNo, orderNos));
        // 查询收货地址
        List<Integer> shippingIds = orders.stream().map(Order::getShippingId).collect(Collectors.toList());
        List<Shipping> shippings = shippingService.list(new LambdaQueryWrapper<Shipping>().in(Shipping::getId, shippingIds));

        // 使用lamdba分组构造Map<orderNo,List<OrderItem>>
        Map<Long, List<OrderItem>> orderItemMap = orderItems.stream().collect(Collectors.groupingBy(OrderItem::getOrderNo));
        // 使用lamdba构造Map<shippingId,shipping> key:shippingId value:shipping对象
        Map<Integer, Shipping> shippingMap = shippings.stream().collect(Collectors.toMap(Shipping::getId, shipping -> shipping));

        List<OrderVo> orderVos = new ArrayList<>();
        for (Order order : orders) {
            OrderVo orderVo = buildOrderVo(order, orderItemMap.get(order.getOrderNo()), shippingMap.get(order.getShippingId()));
            orderVos.add(orderVo);
        }
        PageInfo pageInfo = new PageInfo(orders);
        pageInfo.setList(orderVos);
        return R.ok(pageInfo);
    }

    @Override
    @Transactional
    public R<OrderVo> create(Integer userId, Integer shippingId) {
        // 校验收货地址
        // Shipping存在且是该用户的
        Shipping shipping = shippingService.getOne(new LambdaQueryWrapper<Shipping>().eq(Shipping::getId, shippingId).eq(Shipping::getUserId, userId));
        if (shipping == null) {
            return R.error(ResultEnum.SHIPPING_NOT_EXIST);
        }
        // 获取购物车(已选中的商品)
        List<Cart> carts = cartService.carts(Constant.CART_REDIS_KEY + userId)
                .stream().filter(Cart::getProductSelected).collect(Collectors.toList());
        if (CollectionUtil.isEmpty(carts)) {
            return R.error(ResultEnum.CART_SELECTED_IS_EMPTY);
        }
        //获取carts中的products
        Set<Integer> productIds = carts.stream().map(Cart::getProductId).collect(Collectors.toSet());
        List<Product> products = productService.list(new LambdaQueryWrapper<Product>().in(Product::getId, productIds));
        // 构造Map<productId,product> key:productId value:product对象
        Map<Integer, Product> productMap = products.stream().collect(Collectors.toMap(Product::getId, product -> product));
        List<OrderItem> orderItems = new ArrayList<>();
        Long orderNo = snowflake.nextId();
        for (Cart cart : carts) {
            Product product = productMap.get(cart.getProductId());
            if (product == null) {
                return R.error(ResultEnum.PRODUCT_NOT_EXIST);
            }
            // 商品上下架状态
            if (!product.getStatus().equals(Constant.ONE)) {
                return R.error(ResultEnum.PRODUCT_OFF_SALE_OR_DELETED);
            }
            // 商品库存
            if (product.getStock() < cart.getQuantity()) {
                return R.error(ResultEnum.PRODUCT_STOCK_NOT_ENOUGH);
            }
            orderItems.add(buildOrderItem(userId, orderNo, product, cart));
            // 减库存
            product.setStock(product.getStock() - cart.getQuantity());
            productService.updateById(product);
        }
        // 生成订单入库
        Order order = buildOrder(userId, orderNo, shippingId, orderItems);
        this.baseMapper.insert(order);
        orderItemService.saveBatch(orderItems);

        // 更新购物车(删除购买的商品)
        // redis有事务(打包命令)不能回滚,所以放在返回前操作
        for (Cart cart : carts) {
            cartService.delete(userId, cart.getProductId());
        }

        // 构造orderVo
        return R.ok(buildOrderVo(order, orderItems, shipping));
    }

    @Override
    public R<OrderVo> detail(Integer userId, Long orderNo) {
        Order order = this.baseMapper.selectOne(new LambdaQueryWrapper<Order>().eq(Order::getOrderNo, orderNo).eq(Order::getUserId, userId));
        if (order == null) {
            return R.error(ResultEnum.ORDER_NOT_EXIST);
        }
        List<OrderItem> orderItems = orderItemService.list(new LambdaQueryWrapper<OrderItem>().eq(OrderItem::getOrderNo, order.getOrderNo()));
        Shipping shipping = shippingService.getById(order.getShippingId());

        OrderVo orderVo = buildOrderVo(order, orderItems, shipping);
        return R.ok(orderVo);
    }

    @Override
    public R cancel(Integer userId, Long orderNo) {
        Order order = this.baseMapper.selectOne(new LambdaQueryWrapper<Order>().eq(Order::getOrderNo, orderNo).eq(Order::getUserId, userId));
        if (order == null) {
            return R.error(ResultEnum.ORDER_NOT_EXIST);
        }
        // [未付款]状态可以取消
        if (!OrderStatusEnum.NOT_PAY.getDesc().equals(order.getStatus())) {
            return R.error(ResultEnum.ORDER_STATUS_ERROR);
        }
        order.setStatus(OrderStatusEnum.CANCELED.getCode());
        order.setCloseTime(new Date());
        this.baseMapper.updateById(order);
        return R.ok();
    }

    @Override
    public void paid(Long orderNo) {
        Order order = this.baseMapper.selectOne(new LambdaQueryWrapper<Order>().eq(Order::getOrderNo, orderNo));
        if (order == null) {
            throw new RRException("订单不存在,orderNo:" + order.getOrderNo());
        }
        // 只有[未付款]状态可以更新为[已付款]状态
        if (!OrderStatusEnum.NOT_PAY.getCode().equals(order.getStatus())) {
            throw new RRException("订单状态不是[未付款],orderNo:" + order.getOrderNo());
        }
        order.setStatus(OrderStatusEnum.PAID.getCode());
        order.setPaymentTime(new Date());
        int row = this.baseMapper.updateById(order);
        if (row <= 0) {
            throw new RRException("将订单更新为已支付状态失败,订单id:" + order.getOrderNo());
        }
    }

    private OrderVo buildOrderVo(Order order, List<OrderItem> orderItems, Shipping shipping) {
        OrderVo orderVo = new OrderVo();
        BeanUtils.copyProperties(order, orderVo);
        // 改进:order要保存shipping快照
        if (shipping != null) {
            orderVo.setShipping(shipping);
            orderVo.setShippingId(shipping.getId());
        }
        List<OrderItemVo> orderItemVos = orderItems.stream().map(e -> {
            OrderItemVo orderItemVo = new OrderItemVo();
            BeanUtils.copyProperties(e, orderItemVo);
            return orderItemVo;
        }).collect(Collectors.toList());
        orderVo.setOrderItemVos(orderItemVos);
        return orderVo;
    }

    private OrderItem buildOrderItem(Integer userId, Long orderNo, Product product, Cart cart) {
        OrderItem orderItem = new OrderItem();
        orderItem.setUserId(userId);
        orderItem.setOrderNo(orderNo);
        orderItem.setProductId(product.getId());
        orderItem.setProductName(product.getName());
        orderItem.setProductImage(product.getMainImage());
        orderItem.setCurrentUnitPrice(product.getPrice());
        orderItem.setQuantity(cart.getQuantity());
        orderItem.setTotalPrice(product.getPrice().multiply(BigDecimal.valueOf(cart.getQuantity())));
        return orderItem;
    }

    private Order buildOrder(Integer userId, Long orderNo, Integer shippingId, List<OrderItem> orderItems) {
        Order order = new Order();
        order.setOrderNo(orderNo);
        order.setUserId(userId);
        order.setShippingId(shippingId);
        order.setPayment(orderItems.stream().map(OrderItem::getTotalPrice).reduce(new BigDecimal("0"), BigDecimal::add));
        order.setPaymentType(PaymentTypeEnum.PAY_ONLINE.getCode());
        order.setPostage(Constant.ZERO);
        order.setStatus(OrderStatusEnum.NOT_PAY.getCode());
        return order;
    }

}